package it.conv;

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import java.util.concurrent.*;

import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import javax.swing.text.*;

public class ConvGUI {
	
	private static final int MAX_LUN = 1000000;

	private JFrame MainFrame;
	private JTextArea input;
	private JSpinner esn0;
	private JSpinner rate;
	private JSpinner m;
	private JSpinner lunghezza;
	private JButton btnGenera;
	private JButton btnAvvia;
	
	private JCheckBox chckbxRumore;
	private JTextArea coded;
	private JTextArea bscData;
	private JTextArea console;
	private JTextPane decoded;
	
	//AttributeSet per i bit errati
	private MutableAttributeSet siErr;
	//AttributeSet per i bit correttamente decodificati
	private MutableAttributeSet noErr;

	private int totalError;
	private int totalBit;
	private Vector<Integer> bitStream;
	private PrintStream outConsole;

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					ConvGUI window = new ConvGUI();
					window.MainFrame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the application.
	 */
	public ConvGUI() {
		initialize();
	}

	/**
	 * Initialize the contents of the frame.
	 */
	private void initialize() {
		MainFrame = new JFrame();
		MainFrame.setMinimumSize(new Dimension(1000, 600));
		MainFrame.setTitle("Convolutional Encoder/Decoder");
		MainFrame.setBounds(100, 100, 1031, 744);
		MainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		GridBagLayout gridBagLayout = new GridBagLayout();
		gridBagLayout.columnWidths = new int[] {750, 200};
		gridBagLayout.rowHeights = new int[] {550};
		gridBagLayout.columnWeights = new double[]{1.0, 1.0};
		gridBagLayout.rowWeights = new double[]{1.0};
		MainFrame.getContentPane().setLayout(gridBagLayout);
		
		JPanel Data = new JPanel();
		Data.setBorder(new BevelBorder(BevelBorder.LOWERED, null, null, null, null));
		GridBagConstraints gbc_Data = new GridBagConstraints();
		gbc_Data.anchor = GridBagConstraints.EAST;
		gbc_Data.fill = GridBagConstraints.VERTICAL;
		gbc_Data.insets = new Insets(0, 0, 5, 5);
		gbc_Data.gridx = 0;
		gbc_Data.gridy = 0;
		MainFrame.getContentPane().add(Data, gbc_Data);
		GridBagLayout gbl_Data = new GridBagLayout();
		gbl_Data.columnWidths = new int[] {400, 400};
		gbl_Data.rowHeights = new int[] {20, 250, 20, 250, 20, 100};
		gbl_Data.columnWeights = new double[]{1.0, 1.0};
		gbl_Data.rowWeights = new double[]{0.0, 1.0, 0.0, 1.0, 0.0, 1.0};
		Data.setLayout(gbl_Data);
		
		JLabel lblInput = new JLabel("Input");
		lblInput.setBorder(new EmptyBorder(1, 1, 1, 1));
		lblInput.setAlignmentX(Component.CENTER_ALIGNMENT);
		GridBagConstraints gbc_lblInput = new GridBagConstraints();
		gbc_lblInput.fill = GridBagConstraints.VERTICAL;
		gbc_lblInput.insets = new Insets(0, 0, 5, 5);
		gbc_lblInput.gridx = 0;
		gbc_lblInput.gridy = 0;
		Data.add(lblInput, gbc_lblInput);
		
		JScrollPane sPinput = new JScrollPane();
		GridBagConstraints gbc_sPinput = new GridBagConstraints();
		gbc_sPinput.fill = GridBagConstraints.BOTH;
		gbc_sPinput.insets = new Insets(0, 0, 5, 5);
		gbc_sPinput.gridx = 0;
		gbc_sPinput.gridy = 1;
		Data.add(sPinput, gbc_sPinput);
		
		input = new JTextArea();
		input.setLineWrap(true);
		input.setTabSize(0);
		sPinput.setViewportView(input);
		input.addKeyListener(new KeyAdapter() {
			
			public void textErase() {
				for (int i = 0; i < input.getSelectionEnd() - input.getSelectionStart(); i++)
					bitStream.remove(input.getSelectionStart());
			}
			
			@Override
			public void keyTyped(KeyEvent e) {
				
				char c = e.getKeyChar();
				if (input.isFocusOwner() && !e.isControlDown()) {
					if (c == KeyEvent.VK_0) {
						bitStream.add(input.getCaret().getMark(),0);
						if (input.getSelectedText() != null)
							textErase();
					} else if (c == KeyEvent.VK_1) {
						bitStream.add(input.getCaret().getMark(),1);
						if (input.getSelectedText() != null)
							textErase();
					} else
						e.consume();
					if (input.getText().length() >= MAX_LUN)
						e.consume();
				}
				
			}
			
			@Override
			public void keyPressed(KeyEvent e) {
				
				int c = e.getKeyCode();
				if (input.isFocusOwner()) {
					if (e.isControlDown())
						e.consume();
					if (c == KeyEvent.VK_ENTER)
						e.consume();
					if (input.getSelectedText() != null && (c == KeyEvent.VK_BACK_SPACE || c == KeyEvent.VK_DELETE))
						textErase();
					else
						if (!bitStream.isEmpty()) {
							
							if (c == KeyEvent.VK_BACK_SPACE && input.getCaret().getMark() != 0)
								bitStream.remove(input.getCaret().getMark() - 1);
							if (c == KeyEvent.VK_DELETE && input.getCaret().getMark() != input.getText().length())
								bitStream.remove(input.getCaret().getMark());
							
						}
				}
			}
			
		});
		lblInput.setLabelFor(input);
		input.setBorder(new LineBorder(new Color(0, 0, 0)));
		
		JLabel lblCoded = new JLabel("Coded");
		lblCoded.setBorder(new EmptyBorder(1, 1, 1, 1));
		lblCoded.setAlignmentX(Component.CENTER_ALIGNMENT);
		GridBagConstraints gbc_lblCoded = new GridBagConstraints();
		gbc_lblCoded.fill = GridBagConstraints.VERTICAL;
		gbc_lblCoded.insets = new Insets(0, 0, 5, 0);
		gbc_lblCoded.gridx = 1;
		gbc_lblCoded.gridy = 0;
		Data.add(lblCoded, gbc_lblCoded);
		
		JScrollPane sPcoded = new JScrollPane();
		GridBagConstraints gbc_sPcoded = new GridBagConstraints();
		gbc_sPcoded.fill = GridBagConstraints.BOTH;
		gbc_sPcoded.insets = new Insets(0, 0, 5, 0);
		gbc_sPcoded.gridx = 1;
		gbc_sPcoded.gridy = 1;
		Data.add(sPcoded, gbc_sPcoded);
		
		coded = new JTextArea();
		coded.setLineWrap(true);
		coded.setEditable(false);
		coded.setTabSize(0);
		sPcoded.setViewportView(coded);
		coded.setBorder(new LineBorder(new Color(0, 0, 0)));
		lblCoded.setLabelFor(coded);
		
		JLabel lblBscOutput = new JLabel("BSC Output");
		lblBscOutput.setBorder(new EmptyBorder(1, 1, 1, 1));
		lblBscOutput.setAlignmentX(Component.CENTER_ALIGNMENT);
		GridBagConstraints gbc_lblBscOutput = new GridBagConstraints();
		gbc_lblBscOutput.anchor = GridBagConstraints.BELOW_BASELINE;
		gbc_lblBscOutput.insets = new Insets(0, 0, 5, 5);
		gbc_lblBscOutput.gridx = 0;
		gbc_lblBscOutput.gridy = 2;
		Data.add(lblBscOutput, gbc_lblBscOutput);
		
		JScrollPane sPbscData = new JScrollPane();
		GridBagConstraints gbc_sPbscData = new GridBagConstraints();
		gbc_sPbscData.fill = GridBagConstraints.BOTH;
		gbc_sPbscData.insets = new Insets(0, 0, 5, 5);
		gbc_sPbscData.gridx = 0;
		gbc_sPbscData.gridy = 3;
		Data.add(sPbscData, gbc_sPbscData);
		
		bscData = new JTextArea();
		bscData.setWrapStyleWord(true);
		bscData.setLineWrap(true);
		bscData.setTabSize(0);
		sPbscData.setViewportView(bscData);
		bscData.setBorder(new LineBorder(new Color(0, 0, 0)));
		bscData.setEditable(false);
		lblBscOutput.setLabelFor(bscData);
		
		JLabel lblDecoded = new JLabel("Viterbi Decoded");
		lblDecoded.setBorder(new EmptyBorder(1, 1, 1, 1));
		lblDecoded.setAlignmentX(Component.CENTER_ALIGNMENT);
		GridBagConstraints gbc_lblDecoded = new GridBagConstraints();
		gbc_lblDecoded.fill = GridBagConstraints.VERTICAL;
		gbc_lblDecoded.insets = new Insets(0, 0, 5, 0);
		gbc_lblDecoded.gridx = 1;
		gbc_lblDecoded.gridy = 2;
		Data.add(lblDecoded, gbc_lblDecoded);
		
		JScrollPane sPdecoded = new JScrollPane();
		GridBagConstraints gbc_sPdecoded = new GridBagConstraints();
		gbc_sPdecoded.fill = GridBagConstraints.BOTH;
		gbc_sPdecoded.insets = new Insets(0, 0, 5, 0);
		gbc_sPdecoded.gridx = 1;
		gbc_sPdecoded.gridy = 3;
		Data.add(sPdecoded, gbc_sPdecoded);
		
		decoded = new JTextPane();
		sPdecoded.setViewportView(decoded);
		lblDecoded.setLabelFor(decoded);
		decoded.setBorder(new LineBorder(new Color(0, 0, 0)));
		decoded.setEditable(false);
		
		JLabel lblConsole = new JLabel("Console");
		lblConsole.setAlignmentX(Component.CENTER_ALIGNMENT);
		lblConsole.setHorizontalTextPosition(SwingConstants.LEFT);
		lblConsole.setHorizontalAlignment(SwingConstants.CENTER);
		lblConsole.setBorder(new EmptyBorder(1, 1, 1, 1));
		GridBagConstraints gbc_lblConsole = new GridBagConstraints();
		gbc_lblConsole.gridwidth = 2;
		gbc_lblConsole.insets = new Insets(0, 0, 5, 0);
		gbc_lblConsole.gridx = 0;
		gbc_lblConsole.gridy = 4;
		Data.add(lblConsole, gbc_lblConsole);
		
		JScrollPane sPconsole = new JScrollPane();
		GridBagConstraints gbc_sPconsole = new GridBagConstraints();
		gbc_sPconsole.fill = GridBagConstraints.BOTH;
		gbc_sPconsole.gridwidth = 2;
		gbc_sPconsole.insets = new Insets(0, 0, 0, 5);
		gbc_sPconsole.gridx = 0;
		gbc_sPconsole.gridy = 5;
		Data.add(sPconsole, gbc_sPconsole);
		
		console = new JTextArea();
		sPconsole.setViewportView(console);
		console.setLineWrap(true);
		lblConsole.setLabelFor(console);
		console.setEditable(false);
		console.setBorder(new LineBorder(new Color(0, 0, 0)));
		
		JPanel Option = new JPanel();
		Option.setBorder(new BevelBorder(BevelBorder.LOWERED, null, null, null, null));
		GridBagConstraints gbc_Option = new GridBagConstraints();
		gbc_Option.fill = GridBagConstraints.BOTH;
		gbc_Option.insets = new Insets(0, 0, 5, 0);
		gbc_Option.gridx = 1;
		gbc_Option.gridy = 0;
		MainFrame.getContentPane().add(Option, gbc_Option);
		GridBagLayout gbl_Option = new GridBagLayout();
		gbl_Option.columnWidths = new int[] {0, 100, 30, 30, 0};
		gbl_Option.rowHeights = new int[] {30, 30, 30, 30, 50, 50, 30, 50, 0, 0, 0};
		gbl_Option.columnWeights = new double[]{0.0, 1.0, 1.0, 0.0, 0.0};
		gbl_Option.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
		Option.setLayout(gbl_Option);
		
		JLabel lblEsN0 = new JLabel("Es/N0 = ");
		GridBagConstraints gbc_lblEsN0 = new GridBagConstraints();
		gbc_lblEsN0.anchor = GridBagConstraints.EAST;
		gbc_lblEsN0.fill = GridBagConstraints.VERTICAL;
		gbc_lblEsN0.insets = new Insets(0, 0, 5, 5);
		gbc_lblEsN0.gridx = 1;
		gbc_lblEsN0.gridy = 0;
		Option.add(lblEsN0, gbc_lblEsN0);
		
		esn0 = new JSpinner();
		esn0.addChangeListener(new ChangeListener() {
			
			public void stateChanged(ChangeEvent arg0) {
				
				DataGenerator.inizializza((Double)(esn0.getValue()),
						(Integer)(m.getValue()), (Integer)(rate.getValue()),
						outConsole);
				printStatistiche();
				
			}
			
		});
		esn0.setModel(new SpinnerNumberModel(0.5, 0.0, 4.0, 0.005));
		GridBagConstraints gbc_esn0 = new GridBagConstraints();
		gbc_esn0.anchor = GridBagConstraints.EAST;
		gbc_esn0.fill = GridBagConstraints.BOTH;
		gbc_esn0.insets = new Insets(0, 0, 5, 5);
		gbc_esn0.gridx = 2;
		gbc_esn0.gridy = 0;
		Option.add(esn0, gbc_esn0);
		
		JLabel lblRate = new JLabel("Rate \"1/x\" x = ");
		GridBagConstraints gbc_lblRate = new GridBagConstraints();
		gbc_lblRate.gridwidth = 2;
		gbc_lblRate.anchor = GridBagConstraints.EAST;
		gbc_lblRate.fill = GridBagConstraints.VERTICAL;
		gbc_lblRate.insets = new Insets(0, 0, 5, 5);
		gbc_lblRate.gridx = 0;
		gbc_lblRate.gridy = 1;
		Option.add(lblRate, gbc_lblRate);
		
		rate = new JSpinner();
		rate.addChangeListener(new ChangeListener() {
			
			public void stateChanged(ChangeEvent e) {
				
				DataGenerator.inizializza((Double)(esn0.getValue()),
						(Integer)(m.getValue()),(Integer)(rate.getValue()),
						outConsole);
				printStatistiche();
				
			}
			
		});
		rate.setModel(new SpinnerNumberModel(2, 2, 4, 1));
		GridBagConstraints gbc_rate = new GridBagConstraints();
		gbc_rate.anchor = GridBagConstraints.WEST;
		gbc_rate.insets = new Insets(0, 0, 5, 5);
		gbc_rate.fill = GridBagConstraints.VERTICAL;
		gbc_rate.gridx = 2;
		gbc_rate.gridy = 1;
		Option.add(rate, gbc_rate);
		
		JLabel lblM = new JLabel("Memorie m = ");
		GridBagConstraints gbc_lblM = new GridBagConstraints();
		gbc_lblM.gridwidth = 2;
		gbc_lblM.anchor = GridBagConstraints.EAST;
		gbc_lblM.fill = GridBagConstraints.VERTICAL;
		gbc_lblM.insets = new Insets(0, 0, 5, 5);
		gbc_lblM.gridx = 0;
		gbc_lblM.gridy = 2;
		Option.add(lblM, gbc_lblM);
		
		m = new JSpinner();
		m.addChangeListener(new ChangeListener() {
			
			public void stateChanged(ChangeEvent e) {
				
				DataGenerator.inizializza((Double)(esn0.getValue()),
						(Integer)(m.getValue()),(Integer)(rate.getValue()),
						outConsole);
				printStatistiche();
				
			}
			
		});
		m.setModel(new SpinnerNumberModel(3, 3, 10, 1));
		GridBagConstraints gbc_m = new GridBagConstraints();
		gbc_m.anchor = GridBagConstraints.WEST;
		gbc_m.fill = GridBagConstraints.VERTICAL;
		gbc_m.insets = new Insets(0, 0, 5, 5);
		gbc_m.gridx = 2;
		gbc_m.gridy = 2;
		Option.add(m, gbc_m);
		
		JLabel lblLung = new JLabel("Numero bit =");
		GridBagConstraints gbc_lblLung = new GridBagConstraints();
		gbc_lblLung.gridwidth = 2;
		gbc_lblLung.anchor = GridBagConstraints.EAST;
		gbc_lblLung.fill = GridBagConstraints.VERTICAL;
		gbc_lblLung.insets = new Insets(0, 0, 5, 5);
		gbc_lblLung.gridx = 0;
		gbc_lblLung.gridy = 3;
		Option.add(lblLung, gbc_lblLung);
		
		lunghezza = new JSpinner();
		lunghezza.setModel(new SpinnerNumberModel(500, 500, MAX_LUN, 100));
		GridBagConstraints gbc_lunghezza = new GridBagConstraints();
		gbc_lunghezza.fill = GridBagConstraints.BOTH;
		gbc_lunghezza.gridwidth = 2;
		gbc_lunghezza.insets = new Insets(0, 0, 5, 5);
		gbc_lunghezza.gridx = 2;
		gbc_lunghezza.gridy = 3;
		Option.add(lunghezza, gbc_lunghezza);
		
		btnGenera = new JButton("Genera bit");
		btnGenera.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent arg0) {
				
				new Thread(new Runnable(){

					@Override
					public void run() {
						
						btnGenera.setEnabled(false);
						btnAvvia.setEnabled(false);
						
						int[] a = DataGenerator.generaDati((Integer)(lunghezza.getValue()));
						
						bitStream.clear();
						input.setText("");
						for (int i = 0; i < a.length; i++) {
							input.append(String.valueOf(a[i]));
							bitStream.add(a[i]);
						}
						
						btnGenera.setEnabled(true);
						btnAvvia.setEnabled(true);
						
					}
					
				}).start();
				
			}
			
		});
		btnGenera.setAlignmentX(Component.CENTER_ALIGNMENT);
		GridBagConstraints gbc_btnGenera = new GridBagConstraints();
		gbc_btnGenera.gridwidth = 2;
		gbc_btnGenera.fill = GridBagConstraints.BOTH;
		gbc_btnGenera.insets = new Insets(0, 0, 5, 5);
		gbc_btnGenera.gridx = 2;
		gbc_btnGenera.gridy = 5;
		Option.add(btnGenera, gbc_btnGenera);
		
		btnAvvia = new JButton("Avvia");
		btnAvvia.addActionListener(new ActionListener() {
			
			int length = 100000;
			
			int[] pacchetto;
			int[] pakCodificato;
			double[] pakRumore;
			int[] pakDecodificato;
			int err;
			
			public void actionPerformed(ActionEvent arg0) {
				
				if (bitStream.size() > 0) {
					
					/*
					 * Thread di codifica, aggiunta rumore, decodifica separata
					 * dalla scrittura su JTextArea o JTextPane in un esecutore
					 * di thread a parte
					 */
					new Thread(new Runnable(){

						@Override
						public void run() {
							
							btnAvvia.setEnabled(false);
							
							pacchetto = new int[bitStream.size()];
							
							for (int i = 0; i < pacchetto.length; i++)
								pacchetto[i] = bitStream.get(i);
							
							Encoder enc;
							Decoder dec;
							int[][] g = null;
							Integer M = (Integer)(m.getValue());
							Integer out = (Integer)(rate.getValue());
							
							try {
								
								g = PolyGenerator.genera(M, out);
							
							} catch (Exception e) {
								
								JOptionPane.showMessageDialog(MainFrame, e.getMessage());
								
							}
							
							outConsole.println("Codifica convoluzionale...");
							enc = new Encoder(pacchetto, M, g, out, bitStream.size());
							
							//Calcola il tempo di codifica
							long tini = System.currentTimeMillis();
							pakCodificato = enc.encode();
							outConsole.println("Tempo di codifica: " + (System.currentTimeMillis() - tini) + " secondi.");
							
							if (chckbxRumore.isSelected())
								outConsole.println("Aggiunta rumore sui dati...");
							pakRumore = DataGenerator.aggiungiRumore(pakCodificato,
									enc.getLung_canale(),chckbxRumore.isSelected());
							
							outConsole.println("Decodifica Viterbi...");
							dec = new Decoder(pakRumore, M, g, out, bitStream.size());
							//Calcola il tempo di decodifica Viterbi
							tini = System.currentTimeMillis();
							pakDecodificato = dec.decode();
							outConsole.println("Tempo di decodifica: " + (System.currentTimeMillis() - tini) + " secondi.");
							
							if (pakCodificato.length < 100000)
								length = pakCodificato.length;
							
							//Esecutore di thread per la stampa dei bit
							ExecutorService es = Executors.newFixedThreadPool(2);
							
							ArrayList<Callable<Boolean>> thPool = new ArrayList<Callable<Boolean>>();
							thPool.add(new Callable<Boolean>(){
								
								//Thread del pacchetto codificato
								@Override
								public Boolean call() {
									
									coded.setText("");
									for (int i = 0; i < length; i++)
										coded.append("" + pakCodificato[i]);
									
									return true;
									
								}
								
							});
							thPool.add(new Callable<Boolean>(){

								//Thread del pacchetto con il rumore
								@Override
								public Boolean call() {
									
									bscData.setText("");
									for (int i = 0; i < length; i++)
										bscData.append(ConvApp.df2s.format(pakRumore[i]) + " ");
									
									return true;
									
								}
								
							});
							thPool.add(new Callable<Boolean>(){

								//Thread del pacchetto decodificato
								@Override
								public Boolean call() {
									
									err = 0;
									Document doc = decoded.getDocument();
									
									try {
										
										doc.remove(0, doc.getLength());
										
										for (int i = 0; i < pakDecodificato.length; i++) {
											
											doc.insertString(i, String.valueOf(pakDecodificato[i]), null);
											
											if (pacchetto[i] != pakDecodificato[i]) {
												
												decoded.getStyledDocument().setCharacterAttributes(i, 1, siErr, false);
												err++;
												
											} else
												decoded.getStyledDocument().setCharacterAttributes(i, 1, noErr, false);
											
										}
										
										return true;
									
									} catch (BadLocationException e) {
										
										JOptionPane.showMessageDialog(MainFrame, "Errore interno, impossibile visualizzare la stringa decodificata!");
										return false;
										
									}
									
								}
								
							});
							
							try {
								
								//Avvia e aspetta fino al termine di tutti i thread
								java.util.List<Future<Boolean>> ret = es.invokeAll(thPool);
								for (Future<Boolean> i: ret)
									if (!i.get())
										JOptionPane.showMessageDialog(MainFrame, "Non è stato possibile visualizzare uno dei pacchetti!");
								
							} catch (Exception e) {

								JOptionPane.showMessageDialog(MainFrame, "Errore interno, uno dei processi ha smesso di funzionare!");
								
							}
							
							//Stampa delle statistiche
							if (chckbxRumore.isSelected()) {
								
								outConsole.println("Sono avvenuti " + err + " errori non corretti.");
								totalError += err;
								totalBit += bitStream.size();
								
							}
							
							btnAvvia.setEnabled(true);
							
						}
						
					}).start();
					
				} else
					JOptionPane.showMessageDialog(MainFrame, "Il campo input non ha bit!");
				
			}
			
		});
		
		chckbxRumore = new JCheckBox("Aggiunta Rumore");
		chckbxRumore.setSelected(true);
		GridBagConstraints gbc_chckbxRumore = new GridBagConstraints();
		gbc_chckbxRumore.fill = GridBagConstraints.HORIZONTAL;
		gbc_chckbxRumore.gridwidth = 2;
		gbc_chckbxRumore.insets = new Insets(0, 0, 5, 5);
		gbc_chckbxRumore.gridx = 2;
		gbc_chckbxRumore.gridy = 6;
		Option.add(chckbxRumore, gbc_chckbxRumore);
		btnAvvia.setAlignmentX(Component.CENTER_ALIGNMENT);
		GridBagConstraints gbc_btnAvvia = new GridBagConstraints();
		gbc_btnAvvia.insets = new Insets(0, 0, 5, 5);
		gbc_btnAvvia.gridwidth = 2;
		gbc_btnAvvia.fill = GridBagConstraints.BOTH;
		gbc_btnAvvia.gridx = 2;
		gbc_btnAvvia.gridy = 8;
		Option.add(btnAvvia, gbc_btnAvvia);
		
		JLabel lblInfo = new JLabel("In rosso gli errori non corretti");
		lblInfo.setFont(new Font("Dialog", Font.PLAIN, 12));
		GridBagConstraints gbc_lblInfo = new GridBagConstraints();
		gbc_lblInfo.fill = GridBagConstraints.HORIZONTAL;
		gbc_lblInfo.gridwidth = 3;
		gbc_lblInfo.insets = new Insets(0, 0, 5, 5);
		gbc_lblInfo.gridx = 1;
		gbc_lblInfo.gridy = 9;
		Option.add(lblInfo, gbc_lblInfo);
		
		//Inizializzazioni classi create da Mirko e Gianluca
		
		noErr = (MutableAttributeSet)decoded.getInputAttributes().copyAttributes();
		
		siErr = (MutableAttributeSet)decoded.getInputAttributes().copyAttributes();
		StyleConstants.setBold(siErr, true);
		StyleConstants.setForeground(siErr, Color.RED);
		
		totalError = 0;
		totalBit = 0;
		bitStream = new Vector<Integer>();
		outConsole = new PrintStream(new Redirecting(console));
		DataGenerator.inizializza((Double)(esn0.getValue()),
				(Integer)(m.getValue()),(Integer)(rate.getValue()),
				outConsole);
		
		//Fine inizializzazione
		
	}
	
	private void printStatistiche() {
		
		if (totalError != 0 && totalBit != 0) {
			
			double BER = (double)totalError / (double)totalBit;
			outConsole.println("Bit Error Rate = " + BER);
			totalError = 0;
			totalBit = 0;
			
		}	
		
	}
	
	/*
	 * Classe per redirigere l'output sulla jTextArea
	 */
	class Redirecting extends OutputStream {

		private JTextArea jt;
		
		public Redirecting(JTextArea jt) {	this.jt = jt; }

		@Override
		public void write(int b) throws IOException {
			
			jt.append((Character.toString((char)b)));
			
		}
		
	}
	
}
